/*
 * tcpServer.cpp
 *
 *  Created on: 2015年10月23日
 *      Author: linchen
 */

#include <unistd.h>
#include "tcpServer.h"
#include <sys/un.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <fcntl.h>
#include <iostream>
#include <stdio.h>
#include <pthread.h>


TcpServer::~TcpServer ()
{
	close(m_socket_fd);
	this->deactive();
}

TcpServer::TcpServer (int port):ActiveObject("tcpServer"),m_runing(false)
{
		pthread_mutex_init(&m_mutex, NULL);
		m_socket_fd = 0;
		m_port = port;
}

void TcpServer::start()
{
	if(!m_runing)
	{
		m_runing = true;
		init();
		active();
	}
}

void TcpServer::stop()
{
	if(m_runing)
	{
		m_runing = false;
		deactive();
	}
}

void TcpServer::init()
{
		struct sockaddr_in addr;
		std::cout << "Starting on port " << m_port << std::endl;

		memset (&addr, 0, sizeof (addr));
		addr.sin_family = AF_INET;
		addr.sin_port = htons (m_port);
		addr.sin_addr.s_addr = htonl (INADDR_ANY);

		m_socket_fd = socket (AF_INET, SOCK_STREAM, 0);
		if (m_socket_fd == -1)
		{
			std::cout << "TCPServer: Unable to create TCP socket " << std::endl;
			return;
		}

		int opt = 1;
		setsockopt (m_socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt));

		if (bind (m_socket_fd, (struct sockaddr *) &addr, sizeof (addr)) == -1)
		{
			std::cout << "TCPServer: Unable to register server on TCP port " << m_port << ". Server is probably already started or was not cleanly stopped." << std::endl;
			return;
		}

		if (listen (m_socket_fd, 10) == -1)
		{
			std::cout << "TCPServer: Unable to listen on TCP socket" << std::endl;
		}
}


int TcpServer::sendBroadcastMessage(const char *buf, int length)
{
	pthread_mutex_lock(&m_mutex);            // lock the mutex 互斥锁上锁
	for (ClientList_t::iterator iter = m_clientList.begin(); iter != m_clientList.end(); iter++)
	{
		(*iter)->sendmessage(length, buf);
	}
	pthread_mutex_unlock(&m_mutex);            // lock the mutex 互斥锁上锁
	return 0;
}

int TcpServer::run ()
{
	struct sockaddr_in their_addr;
	struct timeval tv;
	socklen_t sin_size;
	fd_set rdfds;
	int new_socket_fd, max_fd, socket_ret, select_ret;
	char socket_recv_buf[1500];

	tv.tv_sec = 3;
	tv.tv_usec = 0;
	FD_ZERO(&rdfds);

	FD_SET(m_socket_fd, &rdfds);  // add socket accept fd
	max_fd = m_socket_fd;

	for (ClientList_t::iterator iter = m_clientList.begin(); iter != m_clientList.end(); iter++)
	{
		int fd = (*iter)->m_connectfd;
	   // 1.add fd to rdfds
	   FD_SET(fd, &rdfds);  // add socket accept fd
	   // 2.find the max fd
	   if(fd > max_fd)
		   max_fd = fd;
	}

	 select_ret = select(max_fd+1, &rdfds, NULL, NULL, &tv);
	 if( select_ret < 0)
	 {
		perror("raw tcp server socket select error");
	 }
	 else if(select_ret > 0)
	 {
		if(FD_ISSET(m_socket_fd, &rdfds))
		{
			sin_size = sizeof(struct sockaddr_in);
			if ((new_socket_fd = accept(m_socket_fd, (struct sockaddr*)&their_addr, &sin_size)) == -1)
			{
				printf("tcpserver accept error socket_fd_m:%d\n", m_socket_fd);
				//continue;
			}
			else
			{
					int optval = 1;
					// 这个写到这个socket的数据马上发送
					setsockopt(new_socket_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(unsigned int));
					setsockopt(new_socket_fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(unsigned int));
					fcntl(new_socket_fd, F_SETFL, O_NONBLOCK);  // 设置文件flag为0，默认，即阻塞状态
					printf("tcpserver tcp new_socket_fd:%d\n",new_socket_fd);
					//printf("TCP server: got connection from %s\n", (char *)inet_ntoa(their_addr.sin_addr));
					ClientConnection *client = new ClientConnection(new_socket_fd);
					pthread_mutex_lock(&m_mutex);            // lock the mutex 互斥锁上锁
					m_clientList.push_back(client);
					pthread_mutex_unlock(&m_mutex);          // unlock the mutex解锁

			}
		}

		for (ClientList_t::iterator iter = m_clientList.begin(); iter != m_clientList.end(); iter++)
		{
			if(FD_ISSET((*iter)->m_connectfd, &rdfds))
			{
				socket_ret = read((*iter)->m_connectfd, socket_recv_buf, sizeof(socket_recv_buf)-1);
				printf("tcp sock_ret:%d\n", socket_ret);
				if (socket_ret > 0)
				{
					(*iter)->readmessage(socket_recv_buf, socket_ret);
				}
				else if(socket_ret == 0)   // connect closed
				{
					perror("tcp socket connect closed\n");
					pthread_mutex_lock(&m_mutex);            // lock the mutex 互斥锁上锁
					m_clientList.remove(*iter);
					pthread_mutex_unlock(&m_mutex);          // unlock the mutex解锁
					delete (*iter);
					break;
				}
				else if(socket_ret < 0)   // connect error
				{
					perror("tcp socket read error\n");
					pthread_mutex_lock(&m_mutex);            // lock the mutex 互斥锁上锁
					m_clientList.remove(*iter);
					pthread_mutex_unlock(&m_mutex);          // unlock the mutex解锁
					delete (*iter);
					break;
				}
			}
		}
	 }
    return 0;
}

ClientConnection::ClientConnection (int fd)
{
	m_connectfd = fd;
	pthread_mutex_init(&m_mutex, NULL);
}

ClientConnection::~ClientConnection()
{
    close (m_connectfd);
}

int ClientConnection::sendmessage (int size, const char * msg)
{
	pthread_mutex_lock(&m_mutex);            // lock the mutex 互斥锁上锁
    int i;
    int start = 0;
    while (start < size)
    {
		//printf("write fd:%d\n", connectfd_m);
		i = write (m_connectfd, msg + start, size - start);

		if (i <= 0)
		{
			// because the socket is noblock
			if(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
			{
				i=0;
			}
			else
			{
				pthread_mutex_unlock(&m_mutex);          // unlock the mutex解锁
				return -1;
			}
		}
		start += i;
    }
	pthread_mutex_unlock(&m_mutex);          // unlock the mutex解锁
    return 0;
}

int ClientConnection::readmessage (char *buf, int length)
{
/*
		if(length > 0)
		{
			std::string tstr(buf, length);
			msgbuf_m.append(tstr); // = tstr.substr(len+1);

			while (msgbuf_m.size() > 0)
			{
				// we have already some data in the message buffer
				std::string::size_type len = msgbuf_m.find_first_of('\004');
				if (std::string::npos != len)
				{
					// Complete message in the buffer
					std::cout<<"--read complete message--"<<std::endl;
					msg_m = msgbuf_m.substr(0, len);
					//run(); // process message
					msgbuf_m.erase(0, len+1);
					std::cout<<"--process message complete--"<<std::endl;
				}
				else
				{
					return 0;
				}
			}
		}
*/
    return 0;
}

